package com.example.video.demos.web;

import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.aliyun.auth.credentials.Credential;
import com.aliyun.auth.credentials.provider.StaticCredentialProvider;
import com.aliyun.sdk.gateway.pop.Configuration;
import com.aliyun.sdk.gateway.pop.auth.SignatureVersion;
import com.aliyun.sdk.service.quanmiaolightapp20240801.models.*;
import darabonba.core.client.ClientOverrideConfiguration;
import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.Test;

import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.function.Consumer;
import java.util.stream.Collectors;

public class VideoAnalysisAsyncTest {

    /**
     * 业务空间唯一标识：百炼控制台查看
     */
    private String workspaceId = "llm-jvd1vmnm6ag7oem0";

    /**
     * 视频理解在线、异步任务参数
     */
    private String runVideoAnalysisParam = "{\"videoUrl\":\"oss://default/aimiaobi-service-prod/aimiaobi/videoAnalysis/1895432304601054_10938023/1895432304601054_1895432304601054_8961ed7f04594d89be71000261669015.mp4\",\"generateOptions\":[\"videoAnalysis\",\"videoGenerate\",\"videoCaption\",\"videoMindMappingGenerate\",\"videoTitleGenerate\"],\"videoModelCustomPromptTemplate\":\"# 角色\\n你是一名视频分析师，擅长对各种视频片段进行理解。\\n\\n# 任务描述\\n给你一个视频片段的多张关键帧图片，请你完成以下任务。\\n- 输出每张图片的画面信息，包括人物、物体、动作、文字、字幕、镜头语言、一句话总结等。\\n- 把每张图片的信息串联起来，生成视频的详细概述，还原该片段的剧情。\\n\\n# 限制\\n- 分析范围严格限定于提供的视频子片段，不涉及视频之外的任何推测或背景信息。\\n- 总结时需严格依据视频内容，不可添加个人臆测或创意性内容。\\n- 保持对所有视频元素（尤其是文字和字幕）的高保真还原，避免信息遗漏或误解。\\n\\n# 输入数据\\n## 视频片段ASR信息  (如果输入为空则忽略ASR信息)\\n{videoAsrText}\\n\\n## 视频补充信息 (可能对你理解该片段有帮助，如果输入为空则忽略补充信息)\\n{videoExtraInfo}\\n\\n## 视频片段中出现的角色信息 (如果输入为空则忽略)\\n{rolesText}\\n\\n# 输出格式\\n直接按照任务目标里即可，先输出每张图片的描述，再串联起来输出整个视频片段的剧情。\",\"textProcessTasks\":[{\"modelId\":\"qwen-max-latest\",\"modelCustomPromptTemplate\":\"# 角色\\n你是一名专业的短视频文案创作专家，擅长根据视频内容生成极具吸引力的售卖文案。\\n擅长串联以特定格式呈现的、视频的每一帧内容文字描述，还原出整个视频的详细剧情，并完成分配的任务。\\n\\n# 任务目标\\n首先结合输入数据串联、还原出整个视频的详细剧情。\\n仔细阅读视频每一帧文字描述，包括画面信息、动作、镜头语言、一句话总结以及视频片段详细概述等部分。从这些描述中提取关键元素，如产品特点、应用场景。\\n创作短视频售卖文案，要求：开篇要迅速抓住观众注意力，通过提出引人思考的问题或者描绘吸引人的场景引入产品。\\n文案主体部分详细且生动地阐述产品特点与优势，结合提取的关键元素，用形象化的语言描述，比如将产品效果比喻成璀璨流星等，让观众能直观感受到产品的价值。\\n在描述应用场景时，要让观众产生代入感，仿佛自己正使用该产品解决实际问题。\\n文案结尾部分要有力地促成购买行动，用简洁且有号召力的语言，如 “别再犹豫，赶快下单” 等，激发观众购买欲望。\\n整体文案风格要亲切自然、富有感染力，字数根据内容丰富度合理控制，以达到最佳的销售宣传效果 。\\n\\n# 限制\\n1.如出现语法上错误，或逻辑不通，请直接修改\\n2.在视频分镜中，如果包含台词，可能会出现说话者与其所说内容不匹配的情况。因此，必须根据剧情的进展，准确判断每段台词的真实说话者\\n3.如果视频分镜中无台词，请根据视频音频文字为其匹配台词\\n4.修改后的故事请适当保留视频分镜中对人物、场景的描写\\n5.帮忙润色一下故事，使其更具逻辑性\\n6.结合视频分镜中的人物外观特点，如果有外观相近的人物是同一个角色。因此，需要将不同分镜中的人物角色统一。\\n\\n# 输入数据\\n## 资料一：视频分镜信息 (视频各镜头的视觉描述信息)\\n{videoAnalysisText}\\n\\n## 资料二：视频ASR转录信息 (未标注出说话者，可能有错误和遗漏，如果没有输入ASR，则忽略此信息)\\n{videoAsrText}\\n\\n## 资料三：视频补充信息 (如果输入为空则忽略补充信息)\\n{videoExtraInfo}\\n\\n# 输出格式\\n直接输出短视频售卖文案，不要输出其他信息。\\n\\n\"}],\"videoModelId\":\"qwen-vl-max-latest\",\"language\":\"chinese\",\"workspaceId\":\"llm-jvd1vmnm6ag7oem0\",\"videoExtraInfo\":\"这是一个有关手电筒介绍的视频，重点是介绍手电筒的效果\",\"frameSampleMethod\":{\"methodName\":\"standard\"}}";

    public static com.aliyun.sdk.service.quanmiaolightapp20240801.AsyncClient lightAppClient() {
        //accessKeyId
        String accessKeyId = System.getenv("accessKeyId");

        //accessKeySecret
        String accessKeySecret = System.getenv("accessKeySecret");

        //域名
        String domain = "quanmiaolightapp.cn-beijing.aliyuncs.com";
        Credential credential = Credential.builder().accessKeyId(accessKeyId).accessKeySecret(accessKeySecret).build();
        return com.aliyun.sdk.service.quanmiaolightapp20240801.AsyncClient.builder().credentialsProvider(StaticCredentialProvider.create(credential))
                .serviceConfiguration(Configuration.create().setSignatureVersion(SignatureVersion.V3))
                .overrideConfiguration(ClientOverrideConfiguration.create().setProtocol("HTTPS")
                        .setEndpointOverride(domain))
                .build();
    }

    /**
     * 提交视频理解异步任务
     */
    @Test
    public void submitVideoAnalysisTask() throws ExecutionException, InterruptedException {
        com.aliyun.sdk.service.quanmiaolightapp20240801.AsyncClient asyncClient = lightAppClient();

        JSONObject param = JSONObject.parseObject(runVideoAnalysisParam);

        SubmitVideoAnalysisTaskRequest.Builder builder = SubmitVideoAnalysisTaskRequest.builder();

        //视频地址
        setStringParam(param, "videoUrl", builder::videoUrl);
        //视频补充信息
        setStringParam(param, "videoExtraInfo", builder::videoExtraInfo);
        //vl模型id
        setStringParam(param, "videoModelId", builder::videoModelId);
        //vl模型自定义模板
        setStringParam(param, "videoModelCustomPromptTemplate", builder::videoModelCustomPromptTemplate);
        //llm模型id
        setStringParam(param, "modelId", builder::modelId);
        //llm模型自定义模板
        setStringParam(param, "modelCustomPromptTemplate", builder::modelCustomPromptTemplate);
        //生成选项
        setListStringParam(param, "generateOptions", builder::generateOptions);
        //视频语言：由于asr识别
        setStringParam(param, "language", builder::language);
        //抽帧方式
        JSONObject frameSampleMethod = param.getJSONObject("frameSampleMethod");
        if (frameSampleMethod != null) {
            SubmitVideoAnalysisTaskRequest.FrameSampleMethod.Builder builderInner = SubmitVideoAnalysisTaskRequest.FrameSampleMethod.builder();
            setStringParam(frameSampleMethod, "methodName", builderInner::methodName);
            setIntegerParam(frameSampleMethod, "pixel", builderInner::pixel);
            setDoubleParam(frameSampleMethod, "interval", builderInner::interval);
            builder.frameSampleMethod(builderInner.build());
        }
        //识别视频中的人物身份
        JSONArray videoRoles = param.getJSONArray("videoRoles");
        if (videoRoles != null && !videoRoles.isEmpty()) {
            builder.videoRoles(videoRoles.stream().map(item -> {
                JSONObject videoRole = (JSONObject) item;
                SubmitVideoAnalysisTaskRequest.VideoRoles.Builder builderInner = SubmitVideoAnalysisTaskRequest.VideoRoles.builder();
                setStringParam(videoRole, "roleName", builderInner::roleName);
                setStringParam(videoRole, "roleInfo", builderInner::roleInfo);
                setListStringParam(videoRole, "urls", builderInner::urls);
                return builderInner.build();
            }).collect(Collectors.toList()));
        }

        SubmitVideoAnalysisTaskRequest request = builder.workspaceId(workspaceId).build();

        CompletableFuture<SubmitVideoAnalysisTaskResponse> responseFuture = asyncClient.submitVideoAnalysisTask(request);
        SubmitVideoAnalysisTaskResponse response = responseFuture.get();
        if(response != null && response.getBody().getSuccess() && response.getBody().getData() != null){
            System.out.println("submitVideoAnalysisTask: " + response.getBody());
            System.out.println("taskId: " + response.getBody().getData().getTaskId());
            GetVideoAnalysisTaskResponseBody.Data videoAnalysisTask = null;
            //根据taskId查询任务状态和结果
            for (int i = 0; i < 20; i++) {
                Thread.sleep(30 % 1000);
                videoAnalysisTask = getVideoAnalysisTask(response.getBody().getData().getTaskId());
                System.out.println("videoAnalysisResult: " + JSON.toJSONString(videoAnalysisTask));
                if(videoAnalysisTask == null || videoAnalysisTask.getTaskStatus().equals("SUCCESSED") || videoAnalysisTask.getTaskStatus().equals("FAILED")){
                    break;
                }
            }
            System.out.println("videoAnalysisResult-final: " + JSON.toJSONString(videoAnalysisTask));

        }
    }

    /**
     * 查询视频理解异步任务结果
     */
    public GetVideoAnalysisTaskResponseBody.Data getVideoAnalysisTask(String taskId) throws ExecutionException, InterruptedException {
        com.aliyun.sdk.service.quanmiaolightapp20240801.AsyncClient asyncClient = lightAppClient();

        GetVideoAnalysisTaskRequest.Builder builder = GetVideoAnalysisTaskRequest.builder();

        //任务id
        builder.taskId(taskId);

        GetVideoAnalysisTaskRequest request = builder.workspaceId(workspaceId).build();

        CompletableFuture<GetVideoAnalysisTaskResponse> responseFuture = asyncClient.getVideoAnalysisTask(request);
        GetVideoAnalysisTaskResponse response = responseFuture.get();
        if(response != null && response.getBody().getSuccess()){
            System.out.println("getVideoAnalysisTask: " + response.getBody());
            return response.getBody().getData();
        }
        return null;
    }

    /**
     * 查看视频理解配置
     */
    @Test
    public void getVideoAnalysisConfig() throws ExecutionException, InterruptedException  {
        com.aliyun.sdk.service.quanmiaolightapp20240801.AsyncClient asyncClient = lightAppClient();

        GetVideoAnalysisConfigRequest.Builder builder = GetVideoAnalysisConfigRequest.builder();

        GetVideoAnalysisConfigRequest request = builder.workspaceId(workspaceId).build();

        CompletableFuture<GetVideoAnalysisConfigResponse> responseFuture = asyncClient.getVideoAnalysisConfig(request);
        GetVideoAnalysisConfigResponse response = responseFuture.get();
        if(response != null && response.getBody().getSuccess()){
            System.out.println("getVideoAnalysisConfig: " + response.getBody().getData().getAsyncConcurrency());
        }
    }

    /**
     * 更新视频理解配置
     */
    @Test
    public void updateVideoAnalysisConfig() throws ExecutionException, InterruptedException {
        com.aliyun.sdk.service.quanmiaolightapp20240801.AsyncClient asyncClient = lightAppClient();

        //异步任务并发数
        int asyncConcurrency = 2;
        UpdateVideoAnalysisConfigRequest request = UpdateVideoAnalysisConfigRequest.builder()
                .asyncConcurrency(asyncConcurrency)
                .workspaceId(workspaceId).build();

        CompletableFuture<UpdateVideoAnalysisConfigResponse> responseFuture = asyncClient.updateVideoAnalysisConfig(request);
        UpdateVideoAnalysisConfigResponse response = responseFuture.get();
        if(response != null && response.getBody().getSuccess()){
            System.out.println("updateVideoAnalysisConfig: " + response.getBody());
        }
    }

    private void setDoubleParam(JSONObject param, String name, Consumer<Double> consumer) {
        consumer.accept(param.getDouble(name));
    }

    private void setIntegerParam(JSONObject param, String name, Consumer<Integer> consumer) {
        consumer.accept(param.getInteger(name));
    }

    private static void setStringParam(JSONObject param, String name, Consumer<String> consumer) {
        consumer.accept(param.getString(name));
    }

    private static void setListStringParam(JSONObject param, String name, Consumer<List<String>> consumer) {
        if (param.getJSONArray(name) != null) {
            List<String> value = param.getJSONArray(name).toJavaList(String.class);
            consumer.accept(value);
        }
    }


}
